介紹過在設計分散式架構的八個謬誤後,我們了解分散式架構的複雜度很高,而微服務架構是分散式架構的延伸,因此今天讓我們來看看設計微服務架構的挑戰。
當設計微服務架構時有九件事必須仔細考慮,而這九件事是微服務之所以複雜的原因。
除了之前提過的八個謬誤外,微服務架構還需要考慮系統可用性、架構擴充性等應用程式需要面對的問題,讓我們一個一個看。
當我們想要實作一個通知服務,假設有三種通知,分別是email、簡訊和手機應用通知。那應該要把這三種通知放進同一個微服務中?還是應該讓這三種通知個別變成微服務?
有幾個要點可以評估,首先,他們的程式碼會頻繁修改嗎?如果不會,那全部放在同一個微服務內也未嘗不可。相反的,若是email的內容很常需要修改,那就可以考慮將email單獨變成一個微服務。
此外,如果簡訊通知的數量很龐大,那麼簡訊為了要水平擴展就有可能變成一個獨立的微服務。
要怎麼正確決定微服務的粒度?很困難對吧,這只是第一個挑戰。
共享服務 vs. 共享程式碼
當有一個共用功能時,要怎麼決定放在哪?
舉例來說,當A、B和C有一個認證功能,那這個認證功能應該是一個獨立的微服務?還是應該將程式碼複製給每個用到的服務?
有很多面向可以考慮。如果有一個共用的認證服務,那誰來幫這個服務認證?當認證服務故障,會不會導致單點失效?當有越來越多服務必須認證,這個認證服務能承受嗎?
另一方面,如果將程式碼複製到每個服務上,那當有認證機制更新時該怎麼同步給所有服務?事實上,這問題與資料類似,當每個服務都需要同樣資料時,是要放在一個共享資料庫還是複製到每個服務內?
在上一回我們提過理想的微服務:不要共用資料。因此這題我會選擇複製程式碼(共用程式碼),而不是共用服務。
同步 vs. 非同步
兩個端點間的溝通應該要同步還是非同步?這也有非常多面向要考慮。
非同步明顯有更好的效率和更低的耦合度,當需要水平擴展時,每個獨立服務間也能個別進行擴展。
但同步也有許多優點,例如服務A在服務B故障時能夠更快速的反應,換句話說,同步具有更高的一致性。
這沒有標準答案,端看情境而定。
編排(Orchestration) vs. 編舞(Choreography)
在管理工作流程時,有兩種不同的形式,有點類似剛提到的同步和非同步。
當選擇編排時,在任何子服務故障時,服務A都有辦法更快知道且作出正確對應,也就是有更高的資料一致性。
另一方面,編舞因為低耦合的關係具有更好的擴充性和可用性。當要實作新功能時,編舞能夠有更高的生產力,因為不需要修改服務A,只需要實作新的服務並接上訊息匯流排即可。
基於組件 vs. 策略分支(Tactical forking)
當我們要將一個單體服務解構時,有兩種截然不同的策略。
基於組建解構是傳統的領域驅動開發模式,首先先辨認領域邊界,接著分析依賴關係,最後將獨立出的組件變成領域驅動的微服務。
相反的,策略分支有完全不同的實踐。
首先先放一個閘道器在客戶端和原本的單體間。有注意到嗎?上次提到的拓撲不變謬誤被打破了,為了將單體解構,拓撲必須被改變。
接著,將原本的單體複製一個一模一樣的實體,透過閘道器將要分割的功能導入不同實體上。最後,根據各實體負責的功能不同進行瘦身,最後產生兩個微服務。
同樣的,兩種策略各有優缺。如果是基於組建解構,這會是一個長期抗戰,但最後解構完會得到更加有結構的新微服務。同時原本的單體也會進行不同程度的重構。
反之,策略分支沒有重構的過程,但換來的是能夠更快上線。
嚴格 vs. 鬆散
合約管理指的是兩個服務間溝通媒介的資料格式。
如果選擇鬆散的合約,例如JSON或XML,那麼服務間的耦合會增加,也不容易做到版本控制和向前相容。但優點是更容易開發,尤其是JSON,這是前後端溝通最適合的媒介。
另一方面,使用嚴格的合約,例如Avro或protocol buffer,那麼服務間可以透過綱要就知道資料格式,且新版和舊版的服務更容易並存。
這也是個非常熱門的主題。
首先必須從PACELC中做出取捨,接著又必須要在ACID和BASE間做出選擇,最後還有各種不同的儲存結構,例如鍵值、欄族(columnar)、基於行和基於圖(graph)。
傳統關連式資料庫有個很大的缺點,那就是欠缺水平擴展的能力,但是最近有越來越多技術突破,許多分散式的SQL資料庫可供選擇。但世上沒有完美的解法,我們還是得要了解分散式SQL的優缺點。
每個選擇的背後都是大量經驗的累積,而且真的很困難。
挑選架構的型態是很有趣的,有很多不同的樣式可以選擇,例如:基於服務(Service-oriented)架構、微服務架構、事件驅動架構等。
事實上,一個系統不會只有單一架構型態,通常都是複合的。當要進行選擇時同樣有很多地方需要考慮。
之前我們提過分散式交易了,在設計分散式交易時有三個因素必須考慮。
因此,總共有八種組合,每一個組合都有不同的結構和優劣。
根據我們之前介紹過的分散式交易,我們應該選擇最終一致性和非同步。那麼,我們只需要在編排和編舞中選一個即可。
在上面提到,選擇編舞可以有更低的耦合度和更好的擴充性,但是會有更高的實作複雜度。因為要在編舞中維持一致性是更困難的。
所以設計微服務架構是真的很困難,除了八個謬誤外還有九個挑戰。
這也是為什麼最近研討會的主題漸漸轉向管理軟體複雜度,而不是一味推廣微服務的原因。